package com.game.web.controller.system;

import java.util.*;
import java.util.concurrent.CompletableFuture;

import cn.hutool.core.util.RandomUtil;
import com.game.business.service.HxSevice;
import com.game.common.exception.ServiceException;
import com.game.common.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.game.common.constant.Constants;
import com.game.common.core.domain.AjaxResult;
import com.game.common.core.domain.entity.SysMenu;
import com.game.common.core.domain.entity.SysUser;
import com.game.common.core.domain.model.LoginBody;
import com.game.common.core.domain.model.LoginUser;
import com.game.common.core.text.Convert;
import com.game.framework.web.service.SysLoginService;
import com.game.framework.web.service.SysPermissionService;
import com.game.framework.web.service.TokenService;
import com.game.system.service.ISysConfigService;
import com.game.system.service.ISysMenuService;
import com.game.system.service.ISysUserService;

/**
 * 登录验证
 *
 */
@RestController
public class SysLoginController
{
    @Autowired
    private SysLoginService loginService;

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private YzCodeUtils yzCodeUtils;

    /**
     * 登录方法
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody)
    {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
                loginBody.getUuid());
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }

    /**
     * 微信登录（小程序+app）
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/loginWechat")
    public AjaxResult loginWechat(@RequestBody LoginBody loginBody) throws Exception {
        AjaxResult ajax = AjaxResult.success();
        String type = loginBody.getType();
        // 检查微信code是否存在
        if (StringUtils.isEmpty(loginBody.getWechatCode())) {
            return AjaxResult.error("微信授权code不能为空");
        }
        Map<String, String> wxOpenId =new HashMap<>();
        if("1".equals(type)){
           wxOpenId = WxUtils.getWxOpenId(loginBody.getWechatCode());
        }else{
            wxOpenId = WxUtils.getWxAppOpenId(loginBody.getWechatCode());
        }

        String openId = wxOpenId.get("openId");
        if (StringUtils.isEmpty(openId)) {
            return AjaxResult.error("微信授权失败openId");
        }
        String unionId = wxOpenId.get("unionId");
        if (StringUtils.isEmpty(unionId)) {
            return AjaxResult.error("微信授权失败unionId");
        }
        SysUser sysUser = userService.selectUserByUnionId(unionId);
        if (sysUser == null) {
            // 需要绑定手机号
            return  AjaxResult.success("需要绑定手机号","1");
        }
        String openId_old= sysUser.getOpenId();
        String appOpenId_old = sysUser.getAppOpenId();
        if (StringUtils.isEmpty(openId_old)  && StringUtils.isNotEmpty(openId)  && "1".equals(type) ) {
            sysUser.setOpenId(openId);
        }
        if (StringUtils.isEmpty(appOpenId_old)  && StringUtils.isNotEmpty(openId)  && "2".equals(type) ) {
            sysUser.setAppOpenId(openId);
        }
        userService.updateUserApp(sysUser);
        LoginUser loginUser = new LoginUser(sysUser.getUserId(), sysUser.getDeptId(), sysUser, permissionService.getMenuPermission(sysUser));
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        String token = tokenService.createToken(loginUser);
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }

    /**
     * 手机号密码登录方法
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/loginPhone")
    public AjaxResult loginPhone(@RequestBody LoginBody loginBody){
        AjaxResult ajax = AjaxResult.success();
        // 校验code
//        String s = yzCodeUtils.checkRedisKey(loginBody.getPhonenumber(), loginBody.getCode());
//        if (!StringUtils.isEmpty(s)) {
//            return AjaxResult.error(s);
//        }
        SysUser sysUser = userService.selectUserByPhonenumber(loginBody.getPhonenumber());
        if (sysUser == null) {
            // 需要绑定手机号
            throw  new ServiceException("账号不存在");
        }
        String password=loginBody.getPassword();
        // 验证密码是否正确
        if (!SecurityUtils.matchesPassword(password, sysUser.getPassword())) {
            return AjaxResult.error("密码错误");
        }

        // 检查用户状态
        if (!"0".equals(sysUser.getStatus())) {
            return AjaxResult.error("用户账户已被禁用");
        }
        //
        LoginUser loginUser = new LoginUser(sysUser.getUserId(), sysUser.getDeptId(), sysUser, permissionService.getMenuPermission(sysUser));
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        String token = tokenService.createToken(loginUser);
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }


    @Autowired
    private HxSevice hxSevice;
    /**

    /**
     * 手机号密码注册方法
     *
     */
    @PostMapping("/registerPhone")
    public AjaxResult registerPhone(@RequestBody LoginBody loginBody){
        AjaxResult ajax = AjaxResult.success();
        // 校验code
//        String s = yzCodeUtils.checkRedisKey(loginBody.getPhonenumber(), loginBody.getCode());
////        if (!StringUtils.isEmpty(s)) {
////            return AjaxResult.error(s);
////        }
        // 创建用户对象
        SysUser user = new SysUser();
        user.setNickName(RandomUtil.randomString(10));
        user.setPhonenumber(loginBody.getPhonenumber());
        user.setUserName(loginBody.getPhonenumber()); // 默认使用手机号作为用户名
        user.setPassword(SecurityUtils.encryptPassword(loginBody.getPassword()));
        // 检查手机号是否已注册
        if (!userService.checkPhoneUnique(user)) {
            return AjaxResult.error("该手机号已被注册");
        }

        // 注册用户
        boolean registered = userService.registerUser(user);
        if (!registered) {
            return AjaxResult.error("注册失败");
        }
        // 异步注册环信
        CompletableFuture.runAsync(() -> {
            // 注册环信
            hxSevice.createUser(user.getUserId()+"");
        });

        // 自动登录并生成令牌
        String token = loginService.loginByPhonenumber(loginBody.getPhonenumber(), loginBody.getPassword());
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }


    /**
     * 手机号密码重置密码
     *
     */
    @PostMapping("/resetPasswordByPhone")
    public AjaxResult resetPasswordByPhone(@RequestBody LoginBody loginBody){
        AjaxResult ajax = AjaxResult.success();
        // 校验code
//        String s = yzCodeUtils.checkRedisKey(loginBody.getPhonenumber(), loginBody.getCode());
//        if (!StringUtils.isEmpty(s)) {
//            return AjaxResult.error(s);
//        }

        // 检查手机号是否存在
        SysUser user = userService.selectUserByPhonenumber(loginBody.getPhonenumber());
        if (user == null) {
            return AjaxResult.error("该手机号未注册");
        }

        // 重置密码
        user.setPassword(SecurityUtils.encryptPassword(loginBody.getPassword()));
        int result = userService.resetPwd(user);
        if (result <= 0) {
            return AjaxResult.error("密码重置失败");
        }
        return ajax;
    }


    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping("getInfo")
    public AjaxResult getInfo()
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        if (!loginUser.getPermissions().equals(permissions))
        {
            loginUser.setPermissions(permissions);
            tokenService.refreshToken(loginUser);
        }
        AjaxResult ajax = AjaxResult.success();
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
        ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
        return ajax;
    }

    /**
     * 获取路由信息
     *
     * @return 路由信息
     */
    @GetMapping("getRouters")
    public AjaxResult getRouters()
    {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return AjaxResult.success(menuService.buildMenus(menus));
    }

    // 检查初始密码是否提醒修改
    public boolean initPasswordIsModify(Date pwdUpdateDate)
    {
        Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
        return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
    }

    // 检查密码是否过期
    public boolean passwordIsExpiration(Date pwdUpdateDate)
    {
        Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
        if (passwordValidateDays != null && passwordValidateDays > 0)
        {
            if (StringUtils.isNull(pwdUpdateDate))
            {
                // 如果从未修改过初始密码，直接提醒过期
                return true;
            }
            Date nowDate = DateUtils.getNowDate();
            return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
        }
        return false;
    }
}
